#include <QtTest/QtTest>
#include "ruletest.h"
#include "config/rule.h"

typedef QMap<QString, QStringList> Dictionary;

RuleTest::RuleTest(QObject *parent) :
  QObject(parent)
  {
  }

void RuleTest::initTestCase()
  {
  }

void RuleTest::testApply_data()
  {
  QTest::addColumn<QString>("sPattern");
  QTest::addColumn<QString>("sReplacement");
  QTest::addColumn<QString>("sExp");
  QTest::addColumn<QString>("sResult");
  QTest::addColumn<Position>("posInExp");

  QTest::newRow("1") << "a_%1 b_%2" << "delta(%1,%2) b_%2 a_%1" <<
                        "a_i b_j" << "(delta(i,j) b_j a_i)" << Position(0,0);
  QTest::newRow("2") << "a_%1 b_%2" << "delta(%1.2,%2.2) - b_%1 a_{%1.2,%1.3,%1.1}" <<
                        "a_{i j k} b_{m n}" << "(delta(j,n) b_{i j k} a_{j k i})" << Position(0,0);
  }

void RuleTest::testApply()
  {
  QFETCH(QString, sPattern);
  QFETCH(QString, sReplacement);
  QFETCH(QString, sExp);
  QFETCH(QString, sResult);
  QFETCH(Position, posInExp);

  Expression pattern, replacement, exp, result;
  translator.stringToExp(sPattern, pattern);
  translator.stringToExp(sReplacement, replacement);
  Rule rule(pattern, replacement);
  translator.stringToExp(sExp, exp);
  translator.stringToExp(sResult, result);
  rule.apply(exp, posInExp);
  QCOMPARE(exp, result);
  }

void RuleTest::testCheckCondition_data()
  {
  QTest::addColumn<QString>("sPattern");
  QTest::addColumn<QString>("sExp");  
  QTest::addColumn<Position>("posInExp");
  QTest::addColumn<Condition>("condition");
  QTest::addColumn<bool>("conditionMet");

  QStringList args({"%1", "%2"});
  QTest::newRow("1") << "a_%1 a_%2" << "delta(x,y) a_z - b_y a_x a_z"  << Position(1,1)
            << Condition(Condition::CT_GREATER, args) << false;
  }

void RuleTest::testCheckCondition()
  {
  QFETCH(QString, sPattern);
  QFETCH(QString, sExp);
  QFETCH(Condition, condition);  
  QFETCH(Position, posInExp);
  QFETCH(bool, conditionMet);

  Expression pattern, replacement, exp;
  translator.stringToExp(sPattern, pattern);
  translator.stringToExp("5", replacement);
  Rule rule(pattern, replacement);
  rule.addCondition(condition);

  translator.stringToExp(sExp, exp);
  QCOMPARE(rule.checkCondition(exp, posInExp.first, posInExp.second, condition), conditionMet);
  }

void RuleTest::testCheckForDependencies_data()
  {
  QTest::addColumn<QString>("sPattern");
  QTest::addColumn<QString>("sExp");
  QTest::addColumn<Position>("posInExp");
  QTest::addColumn<bool>("matches");

  QTest::newRow("1") << "a_%1 b_%1" << "a_x a_i b_i" << Position(0,1) << true;
  QTest::newRow("2") << "a_%1 b_%1" << "a_i b_j" << Position(0,0) << false;
  QTest::newRow("3") << "a_%1 b_%2" << "a_i b_i" << Position(0,0) << true;
  QTest::newRow("4") << "a_%1 b_%2" << "a_i b_j" << Position(0,0) << true;
  QTest::newRow("5") << "a_%1 b_%1" << "a_{x y} b_{x y}" << Position(0,0) << true;
  QTest::newRow("6") << "a_%1 b_%1" << "a_{x y} b_{x x}" << Position(0,0) << false;
  QTest::newRow("7") << "a_%1 b_%2" << "a_{x y} b_{x y}" << Position(0,0) << true;
  QTest::newRow("8") << "a_%1 b_%2" << "a_{x y} b_{x x x}" << Position(0,0) << true;
  QTest::newRow("9") << "a_%1 b_%1" << "a_{x x} b_{x x x}" << Position(0,0) << false;
  QTest::newRow("10") << "a_%1 b_%2" << "a_{x y} b_{x x x}" << Position(0,0) << true;
  }

void RuleTest::testCheckForDependencies()
  {
  QFETCH(QString, sPattern);
  QFETCH(QString, sExp);
  QFETCH(Position, posInExp);
  QFETCH(bool, matches);

  Expression pattern, replacement, exp;
  translator.stringToExp(sPattern, pattern);
  translator.stringToExp("5", replacement);
  Rule rule(pattern, replacement);

  translator.stringToExp(sExp, exp);
  QCOMPARE(rule.checkForDependencies(exp, posInExp.first, posInExp.second), matches);
  }

void RuleTest::testFindPatternInExp_data()
  {
  QTest::addColumn<QString>("sPattern");
  QTest::addColumn<QString>("sExp");
  QTest::addColumn<Condition>("condition");
  QTest::addColumn<Position>("position");
    
  QStringList args;
  args << "%2" << "%1";
  QTest::newRow("1") << "a_%1 a_%2" << "delta(x,y) a_z - b_y a_x a_z" 
            << Condition(Condition::CT_GREATER, args) << Position(1,1);
  }
void RuleTest::testFindPatternInExp()
  {
  QFETCH(QString, sPattern);
  QFETCH(QString, sExp);
  QFETCH(Condition, condition);
  QFETCH(Position, position);

  Expression pattern, replacement, exp;
  translator.stringToExp(sPattern, pattern);
  translator.stringToExp("5", replacement);
  Rule rule(pattern, replacement);
  rule.addCondition(condition);

  translator.stringToExp(sExp, exp);
  QCOMPARE(rule.findPatternInExp(exp), position);
  }

void RuleTest::testGetLabelDictionary_data()
  {
  QTest::addColumn<QString>("sPattern");
  QTest::addColumn<QString>("sExp");
  QTest::addColumn<QString>("sInvalidPart");
  QTest::addColumn<Dictionary>("dict");

    {
    Dictionary dict;
    dict.insert("%1", QStringList("i"));
    dict.insert("%2", QStringList("j"));
    dict.insert("%1.0", QStringList("i"));
    dict.insert("%2.0", QStringList("j"));
    QTest::newRow("1") << "a_%1 a_%2" << "delta(x,y) a_z - b_y a_x a_z"
                        << "a_i a_j" << dict;
    }

    {
    Dictionary dict;
    dict.insert("%1", QStringList({"i", "k"}));
    dict.insert("%2", QStringList("j"));
    dict.insert("%1.0", QStringList("i"));
    dict.insert("%1.1", QStringList("k"));
    dict.insert("%2.0", QStringList("j"));
    QTest::newRow("2") << "a_%1 a_%2" << "delta(x,y) a_z - b_y a_x a_z"
                        << "a_{i k} a_j" << dict;
    }
  }

void RuleTest::testGetLabelDictionary()
  {
  QFETCH(QString, sPattern);
  QFETCH(QString, sExp);
  QFETCH(QString, sInvalidPart);
  QFETCH(Dictionary, dict);

  Expression pattern, replacement, invalidPart;
  translator.stringToExp(sPattern, pattern);
  translator.stringToExp("5", replacement);
  Rule rule(pattern, replacement);

  translator.stringToExp(sInvalidPart, invalidPart);
  QMap<QString, QStringList> result = rule.getLabelDictionary(invalidPart);
  QCOMPARE(result, dict);
  }

void RuleTest::cleanupTestCase()
  {
  }
